{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Tce3stUlHN0L"
      },
      "source": [
        "##### Copyright 2020 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "IcfrhafzkZbH"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qFdPvlXBOdUN"
      },
      "source": [
        "# 양자화 인식 훈련 종합 가이드"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MfBg1C5NB3X0"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/model_optimization/guide/quantization/training_comprehensive_guide\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org에서 보기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/model-optimization/blob/master/tensorflow_model_optimization/g3doc/guide/quantization/training_comprehensive_guide.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab에서 실행하기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/model-optimization/blob/master/tensorflow_model_optimization/g3doc/guide/quantization/training_comprehensive_guide.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub에서소스 보기</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/model-optimization/tensorflow_model_optimization/g3doc/guide/quantization/training_comprehensive_guide.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">노트북 다운로드하기</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FbORZA_bQx1G"
      },
      "source": [
        "Keras 양자화 인식 훈련에 관한 종합 가이드를 시작합니다.\n",
        "\n",
        "이 페이지는 다양한 사용 사례를 문서화하고 각각에 대해 API를 사용하는 방법을 보여줍니다. 필요한 API를 알고 나면, [API 문서](https://www.tensorflow.org/model_optimization/api_docs/python/tfmot/quantization)에서 매개변수와 하위 수준의 세부 정보를 찾아보세요.\n",
        "\n",
        "- 양자화 인식 훈련의 이점과 지원되는 기능을 보려면 [개요](https://www.tensorflow.org/model_optimization/guide/quantization/training.md)를 참조하세요.\n",
        "- 단일 엔드 투 엔드 예제는 [양자화 인식 훈련 예제](https://www.tensorflow.org/model_optimization/guide/quantization/training_example.md)를 참조하세요.\n",
        "\n",
        "다음 사용 사례를 다룹니다.\n",
        "\n",
        "- 다음 단계에 따라 8bit 양자화로 모델을 배포합니다.\n",
        "    - 양자화 인식 모델을 정의합니다.\n",
        "    - Keras HDF5 모델의 경우에만 특수 체크포인트 및 역직렬화 로직을 사용합니다. 그렇지 않으면 훈련이 표준입니다.\n",
        "    - 양자화 인식 모델에서 양자화 모델을 만듭니다.\n",
        "- 양자화로 실험합니다.\n",
        "    - 실험용으로 지원되는 배포 경로가 없습니다.\n",
        "    - 사용자 정의 Keras 레이어는 실험 중입니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nuABqZnXVDvO"
      },
      "source": [
        "## 설정"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qqnbd7TOfAq9"
      },
      "source": [
        "필요한 API를 찾고 목적을 이해하기 위해 실행할 수 있지만, 이 섹션은 건너뛸 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "both",
        "id": "lvpH1Hg7ULFz"
      },
      "outputs": [],
      "source": [
        "! pip uninstall -y tensorflow\n",
        "! pip install -q tf-nightly\n",
        "! pip install -q tensorflow-model-optimization\n",
        "\n",
        "import tensorflow as tf\n",
        "import numpy as np\n",
        "import tensorflow_model_optimization as tfmot\n",
        "\n",
        "import tempfile\n",
        "\n",
        "input_shape = [20]\n",
        "x_train = np.random.randn(1, 20).astype(np.float32)\n",
        "y_train = tf.keras.utils.to_categorical(np.random.randn(1), num_classes=20)\n",
        "\n",
        "def setup_model():\n",
        "  model = tf.keras.Sequential([\n",
        "      tf.keras.layers.Dense(20, input_shape=input_shape),\n",
        "      tf.keras.layers.Flatten()\n",
        "  ])\n",
        "  return model\n",
        "\n",
        "def setup_pretrained_weights():\n",
        "  model= setup_model()\n",
        "\n",
        "  model.compile(\n",
        "      loss=tf.keras.losses.categorical_crossentropy,\n",
        "      optimizer='adam',\n",
        "      metrics=['accuracy']\n",
        "  )\n",
        "\n",
        "  model.fit(x_train, y_train)\n",
        "\n",
        "  _, pretrained_weights = tempfile.mkstemp('.tf')\n",
        "\n",
        "  model.save_weights(pretrained_weights)\n",
        "\n",
        "  return pretrained_weights\n",
        "\n",
        "def setup_pretrained_model():\n",
        "  model = setup_model()\n",
        "  pretrained_weights = setup_pretrained_weights()\n",
        "  model.load_weights(pretrained_weights)\n",
        "  return model\n",
        "\n",
        "setup_model()\n",
        "pretrained_weights = setup_pretrained_weights()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dTHLMLV-ZrUA"
      },
      "source": [
        "##양자화 인식 모델을 정의합니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0U6XAUhIe6re"
      },
      "source": [
        "다음과 같은 방법으로 모델을 정의하면 [개요 페이지](https://www.tensorflow.org/model_optimization/guide/quantization/training.md)에 나열된 백엔드에 배포할 수 있는 경로가 있습니다. 기본적으로 8bit 양자화가 사용됩니다.\n",
        "\n",
        "참고: 양자화 인식 모델은 실제로 양자화되지 않습니다. 양자화된 모델을 만드는 것은 별도의 단계입니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ybigft1fTn4T"
      },
      "source": [
        "### 전체 모델 양자화하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "puZvqnp1xsn-"
      },
      "source": [
        "**사용 사례:**\n",
        "\n",
        "- 하위 클래스화된 모델은 지원되지 않습니다.\n",
        "\n",
        "**모델 정확성의 향상을 위한 팁:**\n",
        "\n",
        "- 정확성을 가장 많이 떨어뜨리는 레이어 양자화를 건너뛰려면 \"일부 레이어 양자화\"를 시도하세요.\n",
        "- 일반적으로 처음부터 훈련하는 것보다 양자화 인식 훈련으로 미세 조정하는 것이 좋습니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_Zhzx_azO1WR"
      },
      "source": [
        "전체 모델이 양자화를 인식하도록 하려면, `tfmot.quantization.keras.quantize_model`을 모델에 적용합니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1s_EK8reOruu"
      },
      "outputs": [],
      "source": [
        "base_model = setup_model()\n",
        "base_model.load_weights(pretrained_weights) # optional but recommended for model accuracy\n",
        "\n",
        "quant_aware_model = tfmot.quantization.keras.quantize_model(base_model)\n",
        "quant_aware_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xTbTLn3dZM7h"
      },
      "source": [
        "### 일부 레이어 양자화하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MbM8o832xTxV"
      },
      "source": [
        "모델을 양자화하면 정확성에 부정적인 영향을 미칠 수 있습니다. 모델의 레이어를 선택적으로 양자화하여 정확성, 속도 및 모델 크기 간의 균형을 탐색할 수 있습니다.\n",
        "\n",
        "**사용 사례:**\n",
        "\n",
        "- 완전히 양자화된 모델(예: EdgeTPU v1, 대부분의 DSP)에서만 잘 동작하는 백엔드에 배포하려면 \"전체 모델 양자화하기\"를 시도하세요.\n",
        "\n",
        "**모델 정확성의 향상을 위한 팁:**\n",
        "\n",
        "- 일반적으로 처음부터 훈련하는 것보다 양자화 인식 훈련으로 미세 조정하는 것이 좋습니다.\n",
        "- 첫 번째 레이어 대신 이후 레이어를 양자화해보세요.\n",
        "- 중요 레이어(예: attention 메커니즘)는 양자화하지 마세요.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3OCbOUWHsE_v"
      },
      "source": [
        "아래 예에서는 `Dense` 레이어만 양자화합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HN0B_QB-ZhE2"
      },
      "outputs": [],
      "source": [
        "# Create a base model\n",
        "base_model = setup_model()\n",
        "base_model.load_weights(pretrained_weights) # optional but recommended for model accuracy\n",
        "\n",
        "# Helper function uses `quantize_annotate_layer` to annotate that only the \n",
        "# Dense layers should be quantized.\n",
        "def apply_quantization_to_dense(layer):\n",
        "  if isinstance(layer, tf.keras.layers.Dense):\n",
        "    return tfmot.quantization.keras.quantize_annotate_layer(layer)\n",
        "  return layer\n",
        "\n",
        "# Use `tf.keras.models.clone_model` to apply `apply_quantization_to_dense` \n",
        "# to the layers of the model.\n",
        "annotated_model = tf.keras.models.clone_model(\n",
        "    base_model,\n",
        "    clone_function=apply_quantization_to_dense,\n",
        ")\n",
        "\n",
        "# Now that the Dense layers are annotated,\n",
        "# `quantize_apply` actually makes the model quantization aware.\n",
        "quant_aware_model = tfmot.quantization.keras.quantize_apply(annotated_model)\n",
        "quant_aware_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HiA28PrrW11H"
      },
      "source": [
        "이 예에서는 레이어 유형을 사용하여 양자화할 레이어를 결정했지만, 특정 레이어를 양자화하는 가장 쉬운 방법은 `name` 속성을 설정하고 `clone_function`에서 해당 이름을 찾는 것입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "CjY_JyB808Da"
      },
      "outputs": [],
      "source": [
        "print(base_model.layers[0].name)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mpb_BydRaSoF"
      },
      "source": [
        "#### 읽기 더 쉽지만 잠재적으로 모델 정확성이 낮음"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2vqXeYffzSHp"
      },
      "source": [
        "양자화 인식 훈련을 통한 미세 조정과 호환되지 않으므로 위의 예보다 정확성이 떨어질 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MQoMH3g3fWwb"
      },
      "source": [
        "**함수형 예**"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7Wow55hg5oiM"
      },
      "outputs": [],
      "source": [
        "# Use `quantize_annotate_layer` to annotate that the `Dense` layer\n",
        "# should be quantized.\n",
        "i = tf.keras.Input(shape=(20,))\n",
        "x = tfmot.quantization.keras.quantize_annotate_layer(tf.keras.layers.Dense(10))(i)\n",
        "o = tf.keras.layers.Flatten()(x)\n",
        "annotated_model = tf.keras.Model(inputs=i, outputs=o)\n",
        "\n",
        "# Use `quantize_apply` to actually make the model quantization aware.\n",
        "quant_aware_model = tfmot.quantization.keras.quantize_apply(annotated_model)\n",
        "\n",
        "# For deployment purposes, the tool adds `QuantizeLayer` after `InputLayer` so that the\n",
        "# quantized model can take in float inputs instead of only uint8.\n",
        "quant_aware_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wIGj-r2of2ls"
      },
      "source": [
        "**순차 예**\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "mQOiDUGgfi4y"
      },
      "outputs": [],
      "source": [
        "# Use `quantize_annotate_layer` to annotate that the `Dense` layer\n",
        "# should be quantized.\n",
        "annotated_model = tf.keras.Sequential([\n",
        "  tfmot.quantization.keras.quantize_annotate_layer(tf.keras.layers.Dense(20, input_shape=input_shape)),\n",
        "  tf.keras.layers.Flatten()\n",
        "])\n",
        "\n",
        "# Use `quantize_apply` to actually make the model quantization aware.\n",
        "quant_aware_model = tfmot.quantization.keras.quantize_apply(annotated_model)\n",
        "\n",
        "quant_aware_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MpvX5IqahV1r"
      },
      "source": [
        "## 체크포인트 및 역직렬화"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GuZ5wlij1dcJ"
      },
      "source": [
        "**사용 사례:** 이 코드는 HDF5 모델 형식(HDF5 가중치 또는 기타 형식이 아님)에만 필요합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6khQg-q7imfH"
      },
      "outputs": [],
      "source": [
        "# Define the model.\n",
        "base_model = setup_model()\n",
        "base_model.load_weights(pretrained_weights) # optional but recommended for model accuracy\n",
        "quant_aware_model = tfmot.quantization.keras.quantize_model(base_model)\n",
        "\n",
        "# Save or checkpoint the model.\n",
        "_, keras_model_file = tempfile.mkstemp('.h5')\n",
        "quant_aware_model.save(keras_model_file)\n",
        "\n",
        "# `quantize_scope` is needed for deserializing HDF5 models.\n",
        "with tfmot.quantization.keras.quantize_scope():\n",
        "  loaded_model = tf.keras.models.load_model(keras_model_file)\n",
        "\n",
        "loaded_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NeNCMDAbnEKU"
      },
      "source": [
        "## 양자화된 모델 생성 및 배포하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "iiYk_KR0rJ2n"
      },
      "source": [
        "일반적으로, 사용할 배포 백엔드에 대한 설명서를 참조하세요.\n",
        "\n",
        "다음은 TFLite 백엔드의 예입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "fbBiEetda3R8"
      },
      "outputs": [],
      "source": [
        "base_model = setup_pretrained_model()\n",
        "quant_aware_model = tfmot.quantization.keras.quantize_model(base_model)\n",
        "\n",
        "# Typically you train the model here.\n",
        "\n",
        "converter = tf.lite.TFLiteConverter.from_keras_model(quant_aware_model)\n",
        "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n",
        "\n",
        "quantized_tflite_model = converter.convert()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v5raSy9ghxkv"
      },
      "source": [
        "## 양자화 실험하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LUGpXIET0cy3"
      },
      "source": [
        "**사용 사례**: 다음 API를 사용하면 지원되는 배포 경로가 없습니다. 이들 기능은 실험적이며 이전 버전과의 호환성이 적용되지 않습니다.\n",
        "\n",
        "- `tfmot.quantization.keras.QuantizeConfig`\n",
        "- `tfmot.quantization.keras.quantizers.Quantizer`\n",
        "- `tfmot.quantization.keras.quantizers.LastValueQuantizer`\n",
        "- `tfmot.quantization.keras.quantizers.MovingAverageQuantizer`"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Q1KI_FCcU7Yn"
      },
      "source": [
        "### 설정: DefaultDenseQuantizeConfig"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "I6nPkJDRUB2G"
      },
      "source": [
        "실험하려면 레이어의 가중치, 활성화 및 출력을 양자화하는 방법을 설명하는 `tfmot.quantization.keras.QuantizeConfig`를 사용해야 합니다.\n",
        "\n",
        "아래는 API 기본값에서 `Dense` 레이어에 사용되는 같은 `QuantizeConfig`를 정의하는 예입니다.\n",
        "\n",
        "이 예제에서 순방향 전파 중에 `get_weights_and_quantizers`에서 반환된 `LastValueQuantizer`는 입력으로 `layer.kernel`을 사용하여 호출되어 출력이 생성됩니다. 출력은 ` set_quantize_weights`에 정의된 로직을 통해 `Dense` 레이어의 원래 순방향 전파에서 `layer.kernel`을 대체합니다. 같은 아이디어가 활성화 및 출력에 적용됩니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "B9SWK5UQT7VQ"
      },
      "outputs": [],
      "source": [
        "LastValueQuantizer = tfmot.quantization.keras.quantizers.LastValueQuantizer\n",
        "MovingAverageQuantizer = tfmot.quantization.keras.quantizers.MovingAverageQuantizer\n",
        "\n",
        "class DefaultDenseQuantizeConfig(tfmot.quantization.keras.QuantizeConfig):\n",
        "    # Configure how to quantize weights.\n",
        "    def get_weights_and_quantizers(self, layer):\n",
        "      return [(layer.kernel, LastValueQuantizer(num_bits=8, symmetric=True, narrow_range=False, per_axis=False))]\n",
        "\n",
        "    # Configure how to quantize activations.\n",
        "    def get_activations_and_quantizers(self, layer):\n",
        "      return [(layer.activation, MovingAverageQuantizer(num_bits=8, symmetric=False, narrow_range=False, per_axis=False))]\n",
        "\n",
        "    def set_quantize_weights(self, layer, quantize_weights):\n",
        "      # Add this line for each item returned in `get_weights_and_quantizers`\n",
        "      # , in the same order\n",
        "      layer.kernel = quantize_weights[0]\n",
        "\n",
        "    def set_quantize_activations(self, layer, quantize_activations):\n",
        "      # Add this line for each item returned in `get_activations_and_quantizers`\n",
        "      # , in the same order.\n",
        "      layer.activation = quantize_activations[0]\n",
        "\n",
        "    # Configure how to quantize outputs (may be equivalent to activations).\n",
        "    def get_output_quantizers(self, layer):\n",
        "      return []\n",
        "\n",
        "    def get_config(self):\n",
        "      return {}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8vJeoGQG9ZX0"
      },
      "source": [
        "### 사용자 정의 Keras 레이어 양자화하기\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YmyhI_bzWb2w"
      },
      "source": [
        "이 예제에서는 `DefaultDenseQuantizeConfig`를 사용하여 `CustomLayer`를 양자화합니다.\n",
        "\n",
        "구성 적용은 \"양자화 실험하기\" 사용 사례에서와 같습니다.\n",
        "\n",
        "- `CustomLayer`에 `tfmot.quantization.keras.quantize_annotate_layer`를 적용하고 `QuantizeConfig`를 전달합니다.\n",
        "- Use `tfmot.quantization.keras.quantize_annotate_model` to continue to quantize the rest of the model with the API defaults.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7_rBOJdyWWEs"
      },
      "outputs": [],
      "source": [
        "quantize_annotate_layer = tfmot.quantization.keras.quantize_annotate_layer\n",
        "quantize_annotate_model = tfmot.quantization.keras.quantize_annotate_model\n",
        "quantize_scope = tfmot.quantization.keras.quantize_scope\n",
        "\n",
        "class CustomLayer(tf.keras.layers.Dense):\n",
        "  pass\n",
        "\n",
        "model = quantize_annotate_model(tf.keras.Sequential([\n",
        "   quantize_annotate_layer(CustomLayer(20, input_shape=(20,)), DefaultDenseQuantizeConfig()),\n",
        "   tf.keras.layers.Flatten()\n",
        "]))\n",
        "\n",
        "# `quantize_apply` requires mentioning `DefaultDenseQuantizeConfig` with `quantize_scope`\n",
        "# as well as the custom Keras layer.\n",
        "with quantize_scope(\n",
        "  {'DefaultDenseQuantizeConfig': DefaultDenseQuantizeConfig,\n",
        "   'CustomLayer': CustomLayer}):\n",
        "  # Use `quantize_apply` to actually make the model quantization aware.\n",
        "  quant_aware_model = tfmot.quantization.keras.quantize_apply(model)\n",
        "\n",
        "quant_aware_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vnMguvVSnUqD"
      },
      "source": [
        "### 양자화 매개변수 수정하기\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BLgH1aFMjTK4"
      },
      "source": [
        "**일반적인 실수:** 바이어스를 32bit 미만으로 양자화하면 일반적으로 모델 정확성이 너무 많이 손상됩니다.\n",
        "\n",
        "이 예제에서는 기본 8bit 대신 가중치에 4bit를 사용하도록 `Dense` 레이어를 수정합니다. 나머지 모델은 계속해서 API 기본값을 사용합니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "77jgBjccnTh6"
      },
      "outputs": [],
      "source": [
        "quantize_annotate_layer = tfmot.quantization.keras.quantize_annotate_layer\n",
        "quantize_annotate_model = tfmot.quantization.keras.quantize_annotate_model\n",
        "quantize_scope = tfmot.quantization.keras.quantize_scope\n",
        "\n",
        "class ModifiedDenseQuantizeConfig(DefaultDenseQuantizeConfig):\n",
        "    # Configure weights to quantize with 4-bit instead of 8-bits.\n",
        "    def get_weights_and_quantizers(self, layer):\n",
        "      return [(layer.kernel, LastValueQuantizer(num_bits=4, symmetric=True, narrow_range=False, per_axis=False))]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "x9JDKhaU3FKe"
      },
      "source": [
        "Applying the configuration is the same across the \"Experiment with quantization\" use cases.\n",
        "\n",
        "- `Dense` 레이어에 `tfmot.quantization.keras.quantize_annotate_layer`를 적용하고 `QuantizeConfig`를 전달합니다.\n",
        "- `tfmot.quantization.keras.quantize_annotate_model`을 사용하여 API 기본값으로 나머지 모델을 계속 양자화합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sq5mfyBF3KxV"
      },
      "outputs": [],
      "source": [
        "model = quantize_annotate_model(tf.keras.Sequential([\n",
        "   # Pass in modified `QuantizeConfig` to modify this Dense layer.\n",
        "   quantize_annotate_layer(tf.keras.layers.Dense(20, input_shape=(20,)), ModifiedDenseQuantizeConfig()),\n",
        "   tf.keras.layers.Flatten()\n",
        "]))\n",
        "\n",
        "# `quantize_apply` requires mentioning `ModifiedDenseQuantizeConfig` with `quantize_scope`:\n",
        "with quantize_scope(\n",
        "  {'ModifiedDenseQuantizeConfig': ModifiedDenseQuantizeConfig}):\n",
        "  # Use `quantize_apply` to actually make the model quantization aware.\n",
        "  quant_aware_model = tfmot.quantization.keras.quantize_apply(model)\n",
        "\n",
        "quant_aware_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bJMKgzh84CCs"
      },
      "source": [
        "### 양자화할 일부 레이어 수정하기\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Z3pij2uO808g"
      },
      "source": [
        "이 예제에서는 활성화 양자화를 건너뛰도록 `Dense` 레이어를 수정합니다. 나머지 모델은 계속해서 API 기본값을 사용합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6BaaJPBR8djV"
      },
      "outputs": [],
      "source": [
        "quantize_annotate_layer = tfmot.quantization.keras.quantize_annotate_layer\n",
        "quantize_annotate_model = tfmot.quantization.keras.quantize_annotate_model\n",
        "quantize_scope = tfmot.quantization.keras.quantize_scope\n",
        "\n",
        "class ModifiedDenseQuantizeConfig(DefaultDenseQuantizeConfig):\n",
        "    def get_activations_and_quantizers(self, layer):\n",
        "      # Skip quantizing activations.\n",
        "      return []\n",
        "\n",
        "    def set_quantize_activations(self, layer, quantize_activations):\n",
        "      # Empty since `get_activaations_and_quantizers` returns\n",
        "      # an empty list.\n",
        "      return"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2OkqHX5r2nT7"
      },
      "source": [
        "구성 적용은 \"양자화 실험하기\" 사용 사례에서와 같습니다.\n",
        "\n",
        "- `Dense` 레이어에 `tfmot.quantization.keras.quantize_annotate_layer`를 적용하고 `QuantizeConfig`를 전달합니다.\n",
        "- `tfmot.quantization.keras.quantize_annotate_model`을 사용하여 API 기본값으로 나머지 모델을 계속 양자화합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Ln9MDIZJ2n3F"
      },
      "outputs": [],
      "source": [
        "model = quantize_annotate_model(tf.keras.Sequential([\n",
        "   # Pass in modified `QuantizeConfig` to modify this Dense layer.\n",
        "   quantize_annotate_layer(tf.keras.layers.Dense(20, input_shape=(20,)), ModifiedDenseQuantizeConfig()),\n",
        "   tf.keras.layers.Flatten()\n",
        "]))\n",
        "\n",
        "# `quantize_apply` requires mentioning `ModifiedDenseQuantizeConfig` with `quantize_scope`:\n",
        "with quantize_scope(\n",
        "  {'ModifiedDenseQuantizeConfig': ModifiedDenseQuantizeConfig}):\n",
        "  # Use `quantize_apply` to actually make the model quantization aware.\n",
        "  quant_aware_model = tfmot.quantization.keras.quantize_apply(model)\n",
        "\n",
        "quant_aware_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yD0sIR6tmmRx"
      },
      "source": [
        "### 사용자 정의 양자화 알고리즘 사용하기\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "I4onhF-H1zsn"
      },
      "source": [
        "`tfmot.quantization.keras.quantizers.Quantizer` 클래스는 입력에 모든 알고리즘을 적용할 수 있는 callable입니다.\n",
        "\n",
        "이 예에서 입력은 가중치이며 `FixedRangeQuantizer` __call__ 함수의 수학을 가중치에 적용합니다. 원래 가중치 값 대신 `FixedRangeQuantizer`의 출력이 이제 가중치를 사용하는 모든 항목으로 전달됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Jt8UioZH49QV"
      },
      "outputs": [],
      "source": [
        "quantize_annotate_layer = tfmot.quantization.keras.quantize_annotate_layer\n",
        "quantize_annotate_model = tfmot.quantization.keras.quantize_annotate_model\n",
        "quantize_scope = tfmot.quantization.keras.quantize_scope\n",
        "\n",
        "class FixedRangeQuantizer(tfmot.quantization.keras.quantizers.Quantizer):\n",
        "  \"\"\"Quantizer which forces outputs to be between -1 and 1.\"\"\"\n",
        "\n",
        "  def build(self, tensor_shape, name, layer):\n",
        "    # Not needed. No new TensorFlow variables needed.\n",
        "    return {}\n",
        "\n",
        "  def __call__(self, inputs, training, weights, **kwargs):\n",
        "    return tf.keras.backend.clip(inputs, -1.0, 1.0)\n",
        "\n",
        "  def get_config(self):\n",
        "    # Not needed. No __init__ parameters to serialize.\n",
        "    return {}\n",
        "\n",
        "\n",
        "class ModifiedDenseQuantizeConfig(DefaultDenseQuantizeConfig):\n",
        "    # Configure weights to quantize with 4-bit instead of 8-bits.\n",
        "    def get_weights_and_quantizers(self, layer):\n",
        "      # Use custom algorithm defined in `FixedRangeQuantizer` instead of default Quantizer.\n",
        "      return [(layer.kernel, FixedRangeQuantizer())]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lu5ZeJ_Y2UxW"
      },
      "source": [
        "Applying the configuration is the same across the \"Experiment with quantization\" use cases.\n",
        "\n",
        "- `Dense` 레이어에 `tfmot.quantization.keras.quantize_annotate_layer`를 적용하고 `QuantizeConfig`를 전달합니다.\n",
        "- Use `tfmot.quantization.keras.quantize_annotate_model` to continue to quantize the rest of the model with the API defaults."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ItC_3mwT2U87"
      },
      "outputs": [],
      "source": [
        "model = quantize_annotate_model(tf.keras.Sequential([\n",
        "   # Pass in modified `QuantizeConfig` to modify this `Dense` layer.\n",
        "   quantize_annotate_layer(tf.keras.layers.Dense(20, input_shape=(20,)), ModifiedDenseQuantizeConfig()),\n",
        "   tf.keras.layers.Flatten()\n",
        "]))\n",
        "\n",
        "# `quantize_apply` requires mentioning `ModifiedDenseQuantizeConfig` with `quantize_scope`:\n",
        "with quantize_scope(\n",
        "  {'ModifiedDenseQuantizeConfig': ModifiedDenseQuantizeConfig}):\n",
        "  # Use `quantize_apply` to actually make the model quantization aware.\n",
        "  quant_aware_model = tfmot.quantization.keras.quantize_apply(model)\n",
        "\n",
        "quant_aware_model.summary()"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [
        "Tce3stUlHN0L"
      ],
      "name": "training_comprehensive_guide.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
